﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;

namespace Chess
{
    public class ConsoleUserInterface
    {
        private readonly Board board;
        private readonly string helpCommand = "?";
        private PieceColor turnColor = PieceColor.White;

        public ConsoleUserInterface(Board board)
        {
            this.board = board;
            Console.WriteLine("Type \"" + helpCommand + "\" for help.");
            PrintBoard();
            do
            {
                Console.Write(turnColor + "'s move: ");
            } while (InterpretCommands(Console.ReadLine()));
            Console.ReadLine();
        }

        private bool InterpretCommands(string input)
        {
            string regexMovePattern = "^[a-hA-H][1-8] [a-hA-H][1-8]( -[BbNnQqRr])?$";
            if (Regex.IsMatch(input, regexMovePattern))
            {
                switch (board.TryMove(ParseControlStringToPosition(input.Substring(0, 2)), ParseControlStringToPosition(input.Substring(3, 2)), turnColor, ParseControlStringToPromotionType(input.Substring(5))))
                {
                    case Status.Invalid: { Console.WriteLine("Invalid move."); break; }
                    case Status.Standard:
                        {
                            PrintBoard();
                            turnColor = Piece.OppositeColor(turnColor);
                            break;
                        }
                    case Status.Check:
                        {
                            PrintBoard();
                            Console.WriteLine(Piece.OppositeColor(turnColor) + " is in check.");
                            turnColor = Piece.OppositeColor(turnColor);
                            break;
                        }
                    case Status.Checkmate:
                        {
                            PrintBoard();
                            Console.WriteLine(Piece.OppositeColor(turnColor) + " is in checkmate.\n" + turnColor + " wins.");
                            return false;
                        }
                    case Status.Stalemate:
                        {
                            PrintBoard();
                            Console.WriteLine("Stalemate.");
                            return false;
                        }
                }
            }
            else if (input == helpCommand)
            {
                string help = "\nB = Bishop\nR = Rook\nK = King\nN = Knight\nQ = Queen\nP = Pawn" +
                "\n\nEnter commands in the form \"[Column][Row] [Column][Row]\" (e.g. \"D4 D6\" without quotes to move a piece from \"D4\" to \"D6\")." +
                "\nOptionally, append a command with \" -[Major Piece Identifier]\" to specify what a pawn will promote into if the move results in a pawn promotion." +
                "\nA pawn will automatically promote into a queen if no major piece identifier is supplied." +
                "\nAn example of a full move command with pawn promotion specifier is \"F7 F8 -N\" to move a pawn from \"F7\" to \"F8\" and promote to a knight instead of a queen." +
                "\nAll commands ignore case.\n";
                Console.WriteLine(help);
            }
            else
            {
                Console.WriteLine("Invalid command.");
            }
            return true;
        }
        private Position ParseControlStringToPosition(string command)
        {
            Debug.Assert(Regex.IsMatch(command, "^[a-hA-H][1-8]$"));
            return new Position((Column)Enum.Parse(typeof(Column), command[0].ToString().ToUpperInvariant()), (Row)(int.Parse(command[1].ToString()) - 1));
        }
        private PieceType ParseControlStringToPromotionType(string command)
        {
            Debug.Assert(Regex.IsMatch(command, "^( -[BbNnQqRr])?$"));
            if (command.Any())
            {
                switch (command[2].ToString().ToUpperInvariant())
                {
                    case "B": { return PieceType.Bishop; }
                    case "N": { return PieceType.Knight; }
                    case "Q": { return PieceType.Queen; }
                    case "R": { return PieceType.Rook; }
                }
            }
            return PieceType.Queen;
        }
        private void PrintBoard()
        {
            Console.WriteLine();
            for (Row row = Row.Eight; row >= Row.One; row--)
            {
                Console.Write(((int)row + 1) + "  ");
                for (Column column = Column.A; column <= Column.H; column++)
                {
                    PrintPiece(board.GetTile(column, row).Piece);
                    Console.Write("  ");
                }
                Console.WriteLine();
                Console.WriteLine();
            }
            Console.Write("   ");
            for (Column column = Column.A; column <= Column.H; column++)
            {
                Console.Write(column + "  ");
            }
            Console.WriteLine();
            Console.WriteLine();
        }
        private void PrintPiece(Piece piece)
        {
            if (piece == null)
            {
                Console.Write("-");
                return;
            }
            switch (piece.PieceColor)
            {
                case PieceColor.Black: { Console.ForegroundColor = ConsoleColor.DarkGray; break; }
                case PieceColor.White: { Console.ForegroundColor = ConsoleColor.White; break; }
            }
            switch (piece.PieceType)
            {
                case PieceType.Bishop: { Console.Write("B"); break; }
                case PieceType.King: { Console.Write("K"); break; }
                case PieceType.Knight: { Console.Write("N"); break; }
                case PieceType.Queen: { Console.Write("Q"); break; }
                case PieceType.Pawn: { Console.Write("P"); break; }
                case PieceType.Rook: { Console.Write("R"); break; }
            }
            Console.ResetColor();
        }
    }
}
